#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include <math.h>

#include "fileperf.hh"
#include "SingleFilePref.h"
#include "iNodePref.h"
#include "FAT32Pref.h"

using namespace std;

const int SUCCESS = 0;
const int FAILURE = -1;

//Checking if there are files which are bigger from the maximal fileSize
int areAllFileSizesOK(const vector<unsigned int> fileSizes,
		unsigned int maximalSize){
	for(unsigned int i=0; i<fileSizes.size(); i++)
	{
		if(fileSizes.at(i)> maximalSize)
		{
			return FAILURE;
		}
	}
	return SUCCESS;
}

int fileSystemPerformance(unsigned int blockSize, unsigned int pointerSize,
		unsigned int maximalSize, storageType type,const std::vector<unsigned int> fileSizes,
		outputStruct *output){
	if(blockSize <=0 || pointerSize <= 0 || maximalSize < 0){
		return FAILURE;
	}
	if(areAllFileSizesOK(fileSizes, maximalSize) == FAILURE)
	{
		cout<<"Files exceed max file size."<<endl;
		return FAILURE;
	}
	if(type != FS_INODE && type != FS_LINKED_LIST){
		return FAILURE;
	}
	SingleFilePref* singleFilePerf;
	if(type == FS_INODE){
		singleFilePerf = new INodePref(maximalSize,blockSize,pointerSize);
	}
	if(type == FS_LINKED_LIST){
		singleFilePerf = new FAT32Pref(maximalSize,blockSize,pointerSize);
	}
	if(singleFilePerf->areConstraintsPossilble() == FAILURE){
		return FAILURE;
	}
	else{
		int emptyFiles = 0;
		output->space = 0;
		output->averageAccessNum= 0;
		for(unsigned int i = 0;i<fileSizes.size();i++){
			outputStruct singleFile;
			if(fileSizes[i] == 0){
				emptyFiles++;
				output->space += blockSize;
			}
			else{
				singleFilePerf->singleFileSystemPerformance(fileSizes[i],&singleFile);
				output->space += singleFile.space;
				output->averageAccessNum += singleFile.averageAccessNum;
			}
		}
		output->averageAccessNum /= (fileSizes.size()- emptyFiles);
		delete(singleFilePerf);
		return SUCCESS;
	}
}

//======================NOT PART OF THE LIBRARY===============================
//TODO: delete

void readInFileSizes(string input,vector<unsigned int>& fileSizes){
	ifstream infile;
	string line;
	infile.open(input.c_str());
	unsigned int val;
	while (!infile.eof())
	{
		getline(infile, line);
		if (line!="")
		{
			val = atoi(line.c_str());
			fileSizes.push_back(val);
		}
	}
	infile.close();
}

void writeToFile(ofstream& output,int index,double linkedList,double iNode){
	output << index << " " << iNode << " " << linkedList<<endl;
}

void writeToFile(ofstream& output,int index,long unsigned int linkedList,long unsigned int iNode){
	output << index << " " << iNode << " " << linkedList<<endl;
}

int main(){
	vector<unsigned int> fileSizes;
//	fileSizes.push_back(2700);
//	outputStruct out;
//	fileSystemPerformance(100,4,pow(10,8),FS_INODE,fileSizes,&out);
//	cout<<"space is: "<< out.space << endl;
//  cout<< "access is: "<<out.averageAccessNum<<endl;
	readInFileSizes("fileSizes.txt",fileSizes);
	outputStruct result;
	ofstream spaceGraphData;
	ofstream accessGraphData;
	spaceGraphData.open("MySpace.txt");
	accessGraphData.open("MyAccess.txt");
	for(int i=100;i<2100;i+=100){
		fileSystemPerformance(i,4,pow(10,8),FS_LINKED_LIST,fileSizes,&result);
		long unsigned int linkedListSpace = result.space;
		double linkedListAccess = result.averageAccessNum;
//		cout<<"finished linked List run"<<i<<endl;
		fileSystemPerformance(i,4,pow(10,8),FS_INODE,fileSizes,&result);
		long unsigned int iNodeSpace = result.space;
		double iNodeAccess = result.averageAccessNum;
//		cout<<"finished iNode run: "<< i <<endl;
		writeToFile(spaceGraphData,i,iNodeSpace,linkedListSpace);
		writeToFile(accessGraphData,i,iNodeAccess,linkedListAccess);
	}
	spaceGraphData.close();
	accessGraphData.close();
	return 0;
}
